package cn.micai.base.concurrent;

import java.util.concurrent.Semaphore;

/**
 * 描述：使用信号量控制对内容池的访问，内容池的大小作为 Semaphore 的构造
 参数传递初始化许可的数目，每个线程获取数据之前必须获得许可，这样就限制了访问内容
 池的线程数目：
 * <p>
 *
 * @author: 赵新国
 * @date: 2018/5/14 15:17
 */
public class PoolSemaphoreDemo {

    private static final int MAX_AVAILABLE = 5;

    private final Semaphore available = new Semaphore(MAX_AVAILABLE, true);

    public static void main(String [] args) {
        final PoolSemaphoreDemo pool = new PoolSemaphoreDemo();
        Runnable runner = new Runnable() {
            @Override
            public void run() {
                try {
                    Object o;
                    o = pool.getItem();
                    System.out.println(Thread.currentThread().getName()+"acquire"+o);
                    Thread.sleep(1000);
                    pool.putItem(o);
                    System.out.println(Thread.currentThread().getName()+"release"+o);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        for (int i=0; i<3; i++) {
            Thread thread = new Thread(runner, "t" + i);
            thread.start();
        }
    }

    // 获取数据，需要得到许可
    public Object getItem() throws InterruptedException {
        available.acquire();
        return getNextAvailableItem();
    }

    // 放回数据，释放许可
    public void putItem(Object x) {
        if (markAsUnused(x)) {
            available.release();
        }
    }

    protected Object[] items = { "AAA", "BBB", "CCC", "DDD", "EEE" };
    protected boolean[] used = new boolean[MAX_AVAILABLE];

    protected synchronized Object getNextAvailableItem() {
        for (int i=0; i<MAX_AVAILABLE; i++) {
            if (!used[i]) {
                used[i] = true;
                return items[i];
            }
        }
        return null;
    }

    protected synchronized boolean markAsUnused(Object item) {
        for (int i=0; i<MAX_AVAILABLE; i++) {
            if (item == items[i]) {
                if (used[i]) {
                    used[i] = false;
                    return true;
                } else {
                    return false;
                }
            }
        }
        return false;
    }

}
